package cn.com.connected.common.aop;

import cn.com.connected.base.exception.BusinessException;
import cn.com.connected.base.exception.ErrorCode;
import cn.com.connected.base.params.page.BaseSearchDto;
import cn.com.connected.common.config.CurrentData;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Created by shaomingsheng on 2017/10/20.
 */
@Aspect
@Component
@Slf4j
@Order(2)
public class ParamsAOP {

  private static String sqlRegex = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(and|exec|execute|insert|select|delete|update|count|drop|%|chr|mid|master|truncate|char|declare|sitename|net user|xp_cmdshell|or|like'|and|exec|execute|insert|create|drop|table|from|grant|use|group_concat|column_name|information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|chr|mid|master|truncate|char|declare|or|--|like)\\b)";
  
  private static Pattern p = Pattern.compile(sqlRegex);

  @Value("${server.package}")
  private String basePackage;

  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
  public void requestMapping(){}

  @Pointcut(value = "execution(* cn.com.connected.controller..*.*(..))")
  public void connectedPackage() {}


  @Order(1)
  @Around("connectedPackage() && requestMapping()")
  public Object handlerLogin(ProceedingJoinPoint joinPoint)  throws Throwable{
    // 获取请求参数数组
    Object[] args = joinPoint.getArgs();
    for (int i = 0; i < args.length; i++) {
      Object obj = args[i];

      //统一处理参数默认值
      if (obj instanceof BaseSearchDto){
        BaseSearchDto bb = (BaseSearchDto)obj;
        if (bb.getSearchOption() == null){
          // 获取目标方法标志（切点方法）
          MethodSignature signature = (MethodSignature) joinPoint.getSignature();
          // 获取方法的参数，是数组，这里获取第一个参数
          Type type = signature.getMethod().getGenericParameterTypes()[i];

          //拥有泛型
          if (type instanceof ParameterizedType){
            // 类型转换
            ParameterizedType parameterizedType = (ParameterizedType) type;
            // 获取到泛型类型，是数组
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            bb.setSearchOption(((Class) actualTypeArguments[0]).newInstance());
          }
        }
      }
    }

    List list = Arrays.stream(args).filter(o->o!=null && (o instanceof String || o.getClass().getPackage().getName().indexOf(basePackage)>-1)).collect(Collectors.toList());
    String argsStr = JSONArray.toJSONString(list);
    Matcher m = p.matcher(argsStr);
    if (m.find()) {
      log.warn("sql 攻击 user:{} paramsBody:{}", CurrentData.getMemberId(),argsStr);

      throw new BusinessException(ErrorCode.SERIOUS_REQUEST);
    }

    // 把数组封装到joinPoint对象返回
    return joinPoint.proceed(args);
  }


}